package com.example.sign.core;

import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.DERSet;
import org.bouncycastle.asn1.DERUTCTime;
import org.bouncycastle.asn1.cms.Attribute;
import org.bouncycastle.asn1.cms.AttributeTable;
import org.bouncycastle.asn1.cms.CMSAttributes;
import org.bouncycastle.cert.jcajce.JcaCertStore;
import org.bouncycastle.cms.*;
import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.DigestCalculatorProvider;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
import org.bouncycastle.util.Store;

import java.security.Security;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Date;
import java.util.List;

import static com.example.sign.constant.P7KeyConstant.PRIVATE_KEY;
import static com.example.sign.constant.P7KeyConstant.PUBLIC_CERT;
import static com.example.sign.core.P7KeyGenerator.restorePrivateKeyByStr;
import static com.example.sign.util.P7SignUtil.generateCert;

/**
 * @author benjamin_5
 * @Description p7签名生成器
 */
public class P7SignGenerator {

    /**
     * 生成p7签名
     * @param data
     * @return
     * @throws Exception
     */
    public static String generate(byte[] data) throws Exception {
        Security.addProvider(new BouncyCastleProvider());
        CMSTypedData msg = new CMSProcessableByteArray(data);
        // 创建签名者信息生成器
        List<X509Certificate> certList = new ArrayList<>();
        X509Certificate cert = generateCert(PUBLIC_CERT);
        certList.add(cert);
        Store certs = new JcaCertStore(certList);
        DigestCalculatorProvider bc = new JcaDigestCalculatorProviderBuilder()
                .setProvider("BC")
                .build();
        ContentSigner signer = new JcaContentSignerBuilder("SHA256withRSA")
                .setProvider("BC")
                .build(restorePrivateKeyByStr(PRIVATE_KEY));

        // 添加签名创建时间
        Date signDate = new Date();
        ASN1EncodableVector attributes = new ASN1EncodableVector();
        attributes.add(new Attribute(CMSAttributes.signingTime, new DERSet(new DERUTCTime(signDate))));
        AttributeTable attributeTable = new AttributeTable(attributes);

        SignerInfoGenerator signerInfoGenerator = new JcaSignerInfoGeneratorBuilder(bc)
                .setSignedAttributeGenerator(new DefaultSignedAttributeTableGenerator(attributeTable))
                .build(signer, cert);
        // 创建签名生成器
        CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
        generator.addSignerInfoGenerator(signerInfoGenerator);
        generator.addCertificates(certs);
        // 生成签名数据
        CMSSignedData signedData = generator.generate(msg, true);
        byte[] signedBytes = signedData.getEncoded();
        return Base64.getEncoder().encodeToString(signedBytes);
    }

}
